/* example from http://barnyard.syr.edu/quickies/led.c */

/* led.c: print out number as if on 7 line led display. I.e., write integer
   given on command line like this:
      _   _       _
   |  _|  _| |_| |_
   | |_   _|   |  _| etc.

   We assume the terminal behaves like a classical teletype. So the top
   lines of all digits have to be printed first, then the middle lines of
   all digits, etc.

   By Terry R. McConnell

compile: cc -o led led.c

If you just want to link in the subroutine print_led that does all the
work, compile with -DNO_MAIN, and declare the following in any source file
that uses the call:

extern void print_led(unsigned long x, char *buf);

Bug: you cannot call repeatedly to print more than one number to a line.
That would require curses or some other terminal API that allows moving the
cursor to a previous line.

*/

#include <stdio.h>
#include <stdlib.h>

#define MAX_DIGITS 32
#define NO_MAIN

/* Print the top line of the digit d into buffer.
   Does not null terminate buffer. */

void topline(int d, char* p) {

    *p++ = ' ';
    switch (d) {

        /* all these have _ on top line */

    case 0:
    case 2:
    case 3:
    case 5:
    case 7:
    case 8:
    case 9:
        *p++ = '_';
        break;
    default:
        *p++ = ' ';
    }
    *p++ = ' ';
}

/* Print the middle line of the digit d into the buffer.
   Does not null terminate. */

void midline(int d, char* p) {

    switch (d) {

        /* those that have leading | on middle line */

    case 0:
    case 4:
    case 5:
    case 6:
    case 8:
    case 9:
        *p++ = '|';
        break;
    default:
        *p++ = ' ';
    }
    switch (d) {

        /* those that have _ on middle line */

    case 2:
    case 3:
    case 4:
    case 5:
    case 6:
    case 8:
    case 9:
        *p++ = '_';
        break;
    default:
        *p++ = ' ';
    }
    switch (d) {

        /* those that have closing | on middle line */

    case 0:
    case 1:
    case 2:
    case 3:
    case 4:
    case 7:
    case 8:
    case 9:
        *p++ = '|';
        break;
    default:
        *p++ = ' ';
    }
}

/* Print the bottom line of the digit d. Does not null terminate. */

void botline(int d, char* p) {

    switch (d) {

        /* those that have leading | on bottom line */

    case 0:
    case 2:
    case 6:
    case 8:
        *p++ = '|';
        break;
    default:
        *p++ = ' ';
    }
    switch (d) {

        /* those that have _ on bottom line */

    case 0:
    case 2:
    case 3:
    case 5:
    case 6:
    case 8:
        *p++ = '_';
        break;
    default:
        *p++ = ' ';
    }
    switch (d) {

        /* those that have closing | on bottom line */

    case 0:
    case 1:
    case 3:
    case 4:
    case 5:
    case 6:
    case 7:
    case 8:
    case 9:
        *p++ = '|';
        break;
    default:
        *p++ = ' ';
    }
}

/* Write the led representation of integer to string buffer. */

void print_led(unsigned long x, char* buf) {

    int i = 0, n;
    static int d[MAX_DIGITS];

    /* extract digits from x */

    n = (x == 0L ? 1 : 0); /* 0 is a digit, hence a special case */

    while (x) {
        d[n++] = (int)(x % 10L);
        if (n >= MAX_DIGITS)
            break;
        x = x / 10L;
    }

    /* print top lines of all digits */

    for (i = n - 1; i >= 0; i--) {
        topline(d[i], buf);
        buf += 3;
        *buf++ = ' ';
    }
    *buf++ = '\n'; /* move teletype to next line */

    /* print middle lines of all digits */

    for (i = n - 1; i >= 0; i--) {
        midline(d[i], buf);
        buf += 3;
        *buf++ = ' ';
    }
    *buf++ = '\n';

    /* print bottom lines of all digits */

    for (i = n - 1; i >= 0; i--) {
        botline(d[i], buf);
        buf += 3;
        *buf++ = ' ';
    }
    *buf++ = '\n';
    *buf = '\0';
}

int main() {
    char buf[5 * MAX_DIGITS];
    print_led(1234567, buf);
    printf("%s\n", buf);

    return 0;
}

#ifndef NO_MAIN
int main(int argc, char** argv) {

    int i = 0, n;
    long x;
    static int d[MAX_DIGITS];
    char buf[5 * MAX_DIGITS];

    if (argc != 2) {
        fprintf(stderr, "led: usage: led integer\n");
        return 1;
    }

    /* fetch argument from command line */

    x = atol(argv[1]);

    /* sanity check */

    if (x < 0) {
        fprintf(stderr, "led: %d must be non-negative\n", x);
        return 1;
    }

    print_led(x, buf);
    printf("%s\n", buf);

    return 0;
}
#endif
